﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  FindItemTask.cs
//    
// Abstract:
//
//  This module implements the FindItemTask class. This handles the task of finding mailbox items via EWS.
//
//--

using System;
using System.Collections.Generic;
using System.Diagnostics;

using Microsoft.OfficeCommunicationsServer.Applications.Common;

namespace Microsoft.EnhancedReminders.Scheduler
{
    /// <summary>
    /// This handles the task of finding mailbox items via EWS.
    /// </summary>
    internal class FindItemTask : ExchangeTask
    {
        // Search expression for finding items
        private readonly SearchExpressionType _searchExpression;

        // Folder to search
        private readonly BaseFolderIdType _parentFolderId;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="taskContext">Task context</param>
        /// <param name="client">WCF proxy for communicating with EWS</param>
        /// <param name="impersonation">Exchange impersonation info</param>
        /// <param name="emailAddress">E-mail address of the user associated with this request</param>
        /// <param name="searchExpression">Search expression for finding the items</param>
        /// <param name="parentFolderId">Parent folder for items to be found</param>
        internal FindItemTask(TaskContext taskContext, ExchangeServicePortType client, ExchangeImpersonationType impersonation, string emailAddress, SearchExpressionType searchExpression, BaseFolderIdType parentFolderId)
            : base(taskContext, client, impersonation, emailAddress)
        {
            Debug.Assert(parentFolderId != null, "parentFolderId != null");

            _searchExpression = searchExpression;
            _parentFolderId = parentFolderId;
        }

        /// <summary>
        /// Requests the items associated with this task.
        /// </summary>
        internal override void Begin()
        {
            Logger.WriteTraceVerbose(Context, "FindItemTask.Begin");

            RestrictionType restriction = null;

            if (_searchExpression != null)
            {
                restriction = new RestrictionType();
                restriction.Item = _searchExpression;
            }

            FindItemType findItem = new FindItemType();
            findItem.ParentFolderIds = new BaseFolderIdType[] { _parentFolderId };
            findItem.ItemShape = new ItemResponseShapeType();
            findItem.ItemShape.BaseShape = DefaultShapeNamesType.IdOnly;
            findItem.Traversal = ItemQueryTraversalType.Shallow;
            findItem.Restriction = restriction;

            FindItemRequest findItemRequest = new FindItemRequest();
            findItemRequest.FindItem = findItem;
            findItemRequest.ExchangeImpersonation = _impersonation;
            findItemRequest.RequestServerVersion = ExchangeUsers.RequestServerVersion;

            try
            {
                // Find the specified mailbox items via EWS
                _client.BeginFindItem(findItemRequest, OnFindItemCompleted, null);
            }
            catch (Exception ex)
            {
                HandleAccessError(ex, "BeginFindItem failed.");
            }
        }

        /// <summary>
        /// Handles completion of the EWS request to find the mailbox items associated with this task.
        /// </summary>
        /// <param name="asyncResult">Status of the asynchronous operation</param>
        private void OnFindItemCompleted(IAsyncResult asyncResult)
        {
            Logger.WriteTraceVerbose(Context, "FindItemTask.OnFindItemCompleted");

            FindItemResponse findItemResponse = GetResponse<FindItemResponse>(asyncResult, _client.EndFindItem, "EndFindItem failed.");

            if (findItemResponse == null)
            {
                return;
            }

            List<ItemIdType> itemIdList = new List<ItemIdType>();

            ResponseMessageType[] findItemResponseMessages = findItemResponse.FindItemResponse1.ResponseMessages.Items;
            Debug.Assert(findItemResponseMessages != null, "findItemResponseMessages != null");

            // Get the list of found items
            foreach (FindItemResponseMessageType responseMessage in findItemResponseMessages)
            {
                if (responseMessage.ResponseClass == ResponseClassType.Success)
                {
                    if (responseMessage.RootFolder.TotalItemsInView > 0)
                    {
                        foreach (ItemType item in responseMessage.RootFolder.Item.AssertCast<ArrayOfRealItemsType>().Items)
                        {
                            itemIdList.Add(item.ItemId);
                        }
                    }
                }
                else
                {
                    Logger.WriteTraceWarning(Context, "Failed to find item.");
                    RaiseCompleted(new TaskCompletedEventArgs(_taskContext, new ExchangeTaskFailedException(Context, responseMessage.ResponseCode, "Failed to find item.")));
                    return;
                }
            }

            RaiseCompleted(new FindItemTaskCompletedEventArgs(_taskContext, itemIdList.Count > 0 ? itemIdList.ToArray() : null));
        }
    }
}
